import kliment.utils._String;

/** Simple math functions
* ...
 * @author	Kliment
 * @version	1.9.64
 */

class kliment.math.Calc {
	
	static public function getPercent(part:Number, total:Number):Number {
		return part / total * 100;
	}
	
	static public function getFromPercent(percent:Number, total:Number):Number {
		return total * .01 * percent;
	}
	
	static public function randomRange(min:Number, max:Number):Number {
		return Math.floor(Math.random() * (max - min + 1)) + min;
	}
	
	static public function sqr(value:Number):Number {
		return value * value;
	}
	
	static public function exponentiation(value:Number, exponent:Number):Number {
		return Math.exp(Math.log(Math.abs(value)) * exponent);
	}
	
	static public function roundDec(value:Number, dec:Number):Number {
		var multiplier:Number = Math.pow(10, dec || 0);
		return Math.round((value || 0) * multiplier) / multiplier;		
	}
	
	static public function inInterval(min:Number, max:Number, value:Number):Number {
		return Math.max(min, Math.min(value, max));
	}
	
	static public function valueFromInterval(start:Number, stop:Number, current_step:Number, count_step:Number, lawFunction:Function):Number {
		return start + lawFunction(current_step, 0, stop - start, count_step);
	}
	
	static public function inIntervalRound(min:Number, max:Number, value:Number):Number {
		if (value > max) 
			return min;
		else if (value < min) 
			return max;
		return value;
	}
	
	static public function intervalRoundNum(min:Number, max:Number, center:Number, value:Number):Number {
		var length:Number = Math.abs(max - min);
		var evenLenght:Number = Number(even(length));
		var halfLength:Number = Math.round(half(length));
		var result:Number = value - center;
		if (result > halfLength) 
			result = result - halfLength * 2 - evenLenght;
		else if (result < -halfLength) 
			result = result + halfLength * 2 + evenLenght;
		return result;
	}
	
	static public function even(value:Number):Boolean {
		return !odd(value);
	}
	
	static public function odd(value:Number):Boolean {
		return Boolean(value % 2);
	}
	
	static public function decimalPart(value:Number, length:Number):Number {
		var valueStr:String = String(value);
		var dotIndex:Number = valueStr.indexOf('.');
		if (dotIndex < 0)
			return 0;
		var result:Number = Number('0' + valueStr.substring(dotIndex, valueStr.length));
		if (length > 0) {
			var m:Number = Number('1' + _String.repeat('0', length));
			result = Math.round(result * m) / m;
		}
		if (String(result).length < length) 
			result = Number('0' + valueStr.substring(dotIndex, valueStr.length).substring(0, length + 1));
		return result;
	}
	
	/**
	 * Return amount of seconds
	 * @param	bytesLoaded
	 * @param	bytesTotal
	 * @param	timeStart
	 * @param	timeNow
	 * @return	Amount of seconds
	 */
	static public function timeLeft(bytesLoaded:Number, bytesTotal:Number, secondsStart:Number, secondsNow:Number):Number {
		return (bytesTotal - bytesLoaded) / (bytesLoaded / ((secondsNow - secondsStart) * .001));
	}
	
	static public function ctg(radian:Number):Number {
		return Math.cos(radian) / Math.sin(radian);
	}
	
	static public function sec(radian:Number):Number {
		return 1 / Math.cos(radian);
	}
	
	static public function cosec(radian:Number):Number {
		return 1 / Math.sin(radian);
	}
	
	static public function half(value:Number, funct:Function):Number {
		value *= .5;
		if (funct)
			value = funct(value)
		return value;
	}
	
	static public function deltaRatio(new_value:Number, value:Number, rate:Number):Number {
		return (new_value - value) * rate;
	}
	
	static public function deltaRatioResult(new_value:Number, value:Number, rate:Number):Number {
		return value + deltaRatio(new_value, value, rate)
	}
	
	static public function nearestValueIndex(numbers:Array, value:Number, vector:Boolean, fromIndex:Number):Number {
		fromIndex = fromIndex || 0;
		var result:Number = -1;
		var dx:Number;
		var minDx:Number = Number.MAX_VALUE;
		var ix:Number;
		var length:Number = numbers.length;
		for (var i:Number = fromIndex; i < length; ++i ) {
			ix = numbers[i];
			dx = Math.abs(value - ix);
			if (dx <= minDx) {
				result = i;
				minDx = dx;
			}
			if (vector && dx > minDx)
				break;
		}
		return result;
	}
	
	static public function nearestValue(numbers:Array, value:Number, vector:Boolean, fromIndex:Number):Number {
		return numbers[nearestValueIndex(numbers, value, vector, fromIndex)];
	}
}